package santiago.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import santiago.exception.InvalidAmountException;
import santiago.exception.NotEnoughCashException;

public class Auction implements Serializable {

    public int PlayerNbr;
    private List<Player> PlayerSequence;
    private List<Player> NoBidPlayers;
    private Map<Player, Integer> Bids;

    public Auction(int PlayerNbr) {
        this.PlayerNbr = PlayerNbr;
        PlayerSequence = new ArrayList<>();
        NoBidPlayers = new ArrayList<>();
        Bids = new HashMap<>();
    }

    public void addBid(Player Player, int Amount) throws InvalidAmountException, NotEnoughCashException {
        if (Amount < 0 || (Bids.containsValue(Amount) && Amount != 0)) {
            throw new InvalidAmountException();
        }
        if (Player.getCash() < Amount) {
            throw new NotEnoughCashException();
        }
        if (Bids.size() < PlayerNbr) {
            Bids.put(Player, Amount);
            putPlayer(Player, Amount);
        }
    }

    private void putPlayer(Player Player, int Amount) {
        if (Amount == 0) {
            NoBidPlayers.add(Player);
        } else {
            if (PlayerSequence.isEmpty()) {
                PlayerSequence.add(Player);
            } else {
                boolean PositionFounded = false;
                for (int i = 0; i < PlayerSequence.size() && !PositionFounded; i++) {
                    Player CurrentPlayer = PlayerSequence.get(i);
                    if (i == PlayerSequence.size() - 1) {
                        if (Amount > Bids.get(CurrentPlayer)) {
                            PlayerSequence.add(0, Player);
                            PositionFounded = true;
                        } else {
                            PlayerSequence.add(Player);
                            PositionFounded = true;
                        }
                    } else {
                        Player NextPlayer = PlayerSequence.get(i + 1);
                        if (Amount < Bids.get(CurrentPlayer) && Amount > Bids.get(NextPlayer)) {
                            PlayerSequence.add(i + 1, Player);
                            PositionFounded = true;
                        }
                    }
                }
            }
        }
        // if last player to bid, add the no bid players to the end of the player sequence
        if (Bids.size() == PlayerNbr) {
            for (int i = NoBidPlayers.size() - 1; i >= 0; i--) {
                PlayerSequence.add(NoBidPlayers.get(i));
            }
        }
    }

    public boolean hasFinished() {
        if (Bids.size() < PlayerNbr) {
            return false;
        }
        return true;
    }

    public Player[] getPlayerSequence() {
        return PlayerSequence.toArray(new Player[PlayerSequence.size()]);
    }

    public int getPlayerBid(Player Player) {
        Integer Bid = Bids.get(Player);
        if (Bid == null) {
            return -1;
        } else {
            return Bid;
        }
    }

    public Player getCanalOverseer() {
        return PlayerSequence.get(PlayerSequence.size() - 1);
    }

    @Override
    public String toString() {
        StringBuilder Builder = new StringBuilder();
        for (Player Player : PlayerSequence) {
            Builder.append(Player.getName()).append(", bid = ").append(Bids.get(Player)).append("\n");
        }
        return Builder.toString();
    }
}
